{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "tags": []
   },
   "source": [
    "# Slicer Jupyter using docker\n",
    "\n",
    "This notebook is shows how views and full application window can be displayed and configured to be used in JupyterLab when Slicer runs in a **docker container** or on a **remote workstation**.\n",
    "\n",
    "It relies on a remote desktop connection and web proxy set up in the [slicer-notebook docker image](https://github.com/Slicer/SlicerDocker/tree/master/slicer-notebook).\n",
    "\n",
    "This notebook can be [run in the web browser via Binder](https://mybinder.org/v2/gh/slicer/SlicerNotebooks/master?filepath=05_SlicerDockerNotebook.ipynb) or locally using a Jupyter server started by this command:\n",
    "\n",
    "    docker run -p 8888:8888 -p49053:49053 -v path/to/my/notebooks:/home/sliceruser/work --rm -ti lassoan/slicer-notebook:latest\n",
    "    \n",
    "Notes:\n",
    "- Replace `path/to/my/notebooks` by the actual local path to your notebook folder.\n",
    "- After the container is started, open `https://127.0.0.1:8888` page in your web browser and copy-paste the token from the docker container's output."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Read an image using SimpleITK\n",
    "\n",
    "import JupyterNotebooksLib as slicernb\n",
    "import slicer\n",
    "import SimpleITK as sitk\n",
    "import sitkUtils as su\n",
    "\n",
    "# Load 3D image using SimpleITK\n",
    "reader = sitk.ImageFileReader()\n",
    "reader.SetFileName(\"data/MRBrainTumor1.nrrd\")\n",
    "image = reader.Execute()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "03771e9b05c448c7a9861e5243e6189b",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "VBox(children=(ViewSliceWidget(children=(FloatSlider(value=0.0, description='Offset', max=78.40000000000003, m…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Get the SimpleITK image into the Slicer scene\n",
    "slicer.mrmlScene.Clear(False)  # clear any previously loaded data from the scene\n",
    "volumeNode = su.PushVolumeToSlicer(image)\n",
    "\n",
    "# Show volume in slice views\n",
    "slicernb.ViewDisplay(\"FourUp\")  # choose a layout where 3 slice views are present\n",
    "slicer.util.setSliceViewerLayers(background=volumeNode, fit=True)  # show this volume in slice viewers\n",
    "\n",
    "# Create slice view widgets in the notebook\n",
    "from ipywidgets import VBox\n",
    "viewWidgets = VBox([slicernb.ViewSliceWidget('Red'), slicernb.ViewSliceWidget('Yellow'), slicernb.ViewSliceWidget('Green')])\n",
    "viewWidgets.layout.max_width=\"400px\"\n",
    "display(viewWidgets)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Apply some processing and view the udpated results\n",
    "\n",
    "# Process image\n",
    "blurFilter = sitk.SmoothingRecursiveGaussianImageFilter()\n",
    "blurFilter.SetSigma(1.0)\n",
    "blurredImage = blurFilter.Execute(image)\n",
    "\n",
    "# Update view widgets (without this, the user would need to move the sliders to get an updated image)\n",
    "su.PushVolumeToSlicer(blurredImage, targetNode=volumeNode)\n",
    "for viewWidget in viewWidgets.children:\n",
    "    viewWidget.sliceView.updateImage()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "        <iframe\n",
       "            width=\"960\"\n",
       "            height=\"768\"\n",
       "            src=\"/desktop/\"\n",
       "            frameborder=\"0\"\n",
       "            allowfullscreen\n",
       "            \n",
       "        ></iframe>\n",
       "        "
      ],
      "text/plain": [
       "<JupyterNotebooksLib.widgets.AppWindow at 0x247fa76d9d0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Set up application window\n",
    "app = slicernb.AppWindow()\n",
    "# Hide patient information from slice view\n",
    "slicernb.showSliceViewAnnotations(False)\n",
    "\n",
    "# Show markups toolbar\n",
    "slicer.modules.markups.toolBarVisible=True\n",
    "\n",
    "# Show volume in 3D view using volume rendering\n",
    "slicernb.showVolumeRendering(volumeNode, True)\n",
    "\n",
    "display(app)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Add markups\n",
    "Before executing the next cell, add markups to the scene: click on the toolbar buttons to create markups, then click in the viewers to place them.\n",
    "\n",
    "If no markups are added then the output of the next cell will be empty."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<h3>Markup: OC</h3>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>label</th>\n",
       "      <th>position.R</th>\n",
       "      <th>position.A</th>\n",
       "      <th>position.S</th>\n",
       "      <th>selected</th>\n",
       "      <th>visible</th>\n",
       "      <th>description</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>OC-1</td>\n",
       "      <td>56.622961</td>\n",
       "      <td>-12.807881</td>\n",
       "      <td>0.7</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>OC-2</td>\n",
       "      <td>-22.919169</td>\n",
       "      <td>-16.178310</td>\n",
       "      <td>0.7</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>OC-3</td>\n",
       "      <td>-22.919169</td>\n",
       "      <td>-16.178310</td>\n",
       "      <td>0.7</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>OC-4</td>\n",
       "      <td>-34.378628</td>\n",
       "      <td>56.622961</td>\n",
       "      <td>0.7</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  label  position.R  position.A  position.S  selected  visible description\n",
       "0  OC-1   56.622961  -12.807881         0.7      True     True            \n",
       "1  OC-2  -22.919169  -16.178310         0.7      True     True            \n",
       "2  OC-3  -22.919169  -16.178310         0.7      True     True            \n",
       "3  OC-4  -34.378628   56.622961         0.7      True     True            "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<h3>Markup: A</h3>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>label</th>\n",
       "      <th>position.R</th>\n",
       "      <th>position.A</th>\n",
       "      <th>position.S</th>\n",
       "      <th>selected</th>\n",
       "      <th>visible</th>\n",
       "      <th>description</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>A-1</td>\n",
       "      <td>30.814281</td>\n",
       "      <td>0.4685</td>\n",
       "      <td>40.719202</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>A-2</td>\n",
       "      <td>57.226737</td>\n",
       "      <td>0.4685</td>\n",
       "      <td>19.149030</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>A-3</td>\n",
       "      <td>44.020509</td>\n",
       "      <td>0.4685</td>\n",
       "      <td>11.225294</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  label  position.R  position.A  position.S  selected  visible description\n",
       "0   A-1   30.814281      0.4685   40.719202      True     True            \n",
       "1   A-2   57.226737      0.4685   19.149030      True     True            \n",
       "2   A-3   44.020509      0.4685   11.225294      True     True            "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<h3>Markup: F</h3>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>label</th>\n",
       "      <th>position.R</th>\n",
       "      <th>position.A</th>\n",
       "      <th>position.S</th>\n",
       "      <th>selected</th>\n",
       "      <th>visible</th>\n",
       "      <th>description</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>F-1</td>\n",
       "      <td>-0.469</td>\n",
       "      <td>84.299504</td>\n",
       "      <td>27.072767</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>F-2</td>\n",
       "      <td>-0.469</td>\n",
       "      <td>-30.594678</td>\n",
       "      <td>9.024256</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>F-3</td>\n",
       "      <td>-0.469</td>\n",
       "      <td>36.757084</td>\n",
       "      <td>-7.263425</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>F-4</td>\n",
       "      <td>-0.469</td>\n",
       "      <td>27.072517</td>\n",
       "      <td>30.594428</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>F-5</td>\n",
       "      <td>-0.469</td>\n",
       "      <td>-14.747204</td>\n",
       "      <td>-45.121278</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>F-6</td>\n",
       "      <td>-0.469</td>\n",
       "      <td>-45.121528</td>\n",
       "      <td>-48.642939</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>F-7</td>\n",
       "      <td>-0.469</td>\n",
       "      <td>-64.050455</td>\n",
       "      <td>-24.431521</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>F-8</td>\n",
       "      <td>-0.469</td>\n",
       "      <td>1.540477</td>\n",
       "      <td>52.164600</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>F-9</td>\n",
       "      <td>-0.469</td>\n",
       "      <td>85.620127</td>\n",
       "      <td>-36.757334</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>F-10</td>\n",
       "      <td>-0.469</td>\n",
       "      <td>36.316876</td>\n",
       "      <td>-40.278995</td>\n",
       "      <td>True</td>\n",
       "      <td>True</td>\n",
       "      <td></td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  label  position.R  position.A  position.S  selected  visible description\n",
       "0   F-1      -0.469   84.299504   27.072767      True     True            \n",
       "1   F-2      -0.469  -30.594678    9.024256      True     True            \n",
       "2   F-3      -0.469   36.757084   -7.263425      True     True            \n",
       "3   F-4      -0.469   27.072517   30.594428      True     True            \n",
       "4   F-5      -0.469  -14.747204  -45.121278      True     True            \n",
       "5   F-6      -0.469  -45.121528  -48.642939      True     True            \n",
       "6   F-7      -0.469  -64.050455  -24.431521      True     True            \n",
       "7   F-8      -0.469    1.540477   52.164600      True     True            \n",
       "8   F-9      -0.469   85.620127  -36.757334      True     True            \n",
       "9  F-10      -0.469   36.316876  -40.278995      True     True            "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Display control point positions in each markup node.\n",
    "from IPython.display import HTML\n",
    "for markupsNode in slicer.util.getNodesByClass(\"vtkMRMLMarkupsNode\"):\n",
    "    display(HTML(f\"<h3>Markup: {markupsNode.GetName()}</h3>\"))\n",
    "    display(slicernb.displayable(markupsNode))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'OC'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "markupsNode = slicer.util.getNodesByClass(\"vtkMRMLMarkupsNode\")[0]\n",
    "markupsNode.GetName()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Show full markups module GUI\n",
    "app.setContents(\"viewers\")\n",
    "slicer.util.findChild(slicer.util.mainWindow(), \"PanelDockWidget\").show()\n",
    "slicer.modules.markups.toolBarVisible=True\n",
    "slicer.util.selectModule(\"Markups\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Show full application GUI\n",
    "app.setContents(\"full\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "e506318ecb204be2a57cacab1234c877",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HTML(value='<a href=\"/desktop/\" target=\"_blank\">\\n<b>Click here</b> to open application window in a new browse…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Create link that shows the application GUI in a new browser tab\n",
    "from ipywidgets import HTML\n",
    "HTML(f\"\"\"<a href=\"{slicernb.AppWindow.defaultDesktopUrl()}\" target=\"_blank\">\n",
    "<b>Click here</b> to open application window in a new browser tab.</a>\"\"\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Show only viewers\n",
    "app.setContents(\"viewers\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "7a95bed771e74a8697dc5ee53155f9f6",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(Button(description='Full', style=ButtonStyle()), Button(description='Viewers', style=ButtonStyl…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from ipywidgets import Button, HBox\n",
    "import JupyterNotebooksLib as slicernb\n",
    "fullButton = Button(description='Full')\n",
    "fullButton.on_click(lambda b: slicernb.AppWindow().setContents(\"full\"))\n",
    "viewersButton = Button(description='Viewers')\n",
    "viewersButton.on_click(lambda b: slicernb.AppWindow().setContents(\"viewers\"))\n",
    "markupsToolbarToggleButton = Button(description='Markups toolbar')\n",
    "def toggleMarkupsToolBar(b):\n",
    "    slicer.modules.markups.toolBarVisible = not slicer.modules.markups.toolBarVisible\n",
    "markupsToolbarToggleButton.on_click(toggleMarkupsToolBar)\n",
    "HBox([fullButton, viewersButton, markupsToolbarToggleButton]) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Run this example in your browser using Binder: [![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/slicer/SlicerNotebooks/master?filepath=05_SlicerDockerNotebook.ipynb)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Slicer 4.13",
   "language": "python",
   "name": "slicer-4.13"
  },
  "language_info": {
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "version": "3.9.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
